<?php

namespace app\api\controller;

use app\api\model\AdminRole;
use app\api\model\AdminToken;
use app\api\model\SystemRole;
use app\common\controller\Api;
use app\common\controller\LoginLog;
use app\common\controller\OperationLog;
use app\common\controller\Util;
use lib\Upload;
use think\captcha\Captcha;
use think\Db;
use think\db\exception\DataNotFoundException;
use think\db\exception\ModelNotFoundException;
use think\Exception;
use think\exception\DbException;
use think\Request;
use think\Response;

/**
 * Admin控制器
 * Class Admin
 * @package app\index\controller
 */
class Admin extends Api
{
    /**
     * 不需要登录权限的方法数组
     * @var string[]
     */
    protected $noNeedLogin = ['login', 'login_by_qq', 'get_openid_by_access_token', 'test', 'generate_captcha'];
    /**
     * 不需要鉴权的方法数组
     * @var array
     */
    protected $noNeedAuth = ['login', 'login_by_qq', 'get_openid_by_access_token', 'test', 'generate_captcha'];
    /**
     * 不需要验证token的方法数组
     * @var array
     */
    protected $noNeedToken = ['login', 'login_by_qq', 'get_openid_by_access_token', 'test', 'generate_captcha'];

    /**
     * 登录方法
     * @throws DbException
     */
    public function login()
    {
        // 接收前端参数
        $param = Request::instance()->post() ?? [];
        // 接收前端ip
        $requestIp = Request::instance()->ip() ?? '0.0.0.0';
        $param['login_ip'] = $requestIp;
        // 校验接收数据合法性
        $validRes = $this->validate($param, 'Admin.login');
        if ($validRes !== true) {
            LoginLog::LoginErrorLog($param, $validRes, time());
            $this->error('error', ['code' => 201, 'data' => $validRes]);
        }
        // 校验用户是否存在
        $row = \app\api\model\Admin::get(['username' => $param['username']]);
        if (empty($row)) {
            LoginLog::LoginErrorLog($param, '登录信息错误', time());
            $this->error('error', ['code' => 201, 'data' => '登录信息错误']);
        }
        // 校验密码是否正确
        if (self::decryptPassword($param['login_password'], $row['salt']) === $row['password']) {
            // 生成token
            $token = md5($row['id'] . time());
            // 开启事务
            Db::startTrans();
            // 更新用户表的token
            try {
                $row['token'] = $token;
                $row['login_time'] = time();
                $row['login_ip'] = $requestIp;
                $row->save();
                // 存入AdminToken表
                $AdminToken = AdminToken::get(['user_id' => $row['id']]) ?? '';
                $AdminToken == '' ?
                    Db::name('admin_token')->insert([
                        'token' => $token,
                        'user_id' => $row['id'],
                        'create_time' => time(),
                        'expire_time' => time() + 2 * 3600
                    ])
                    :
                    Db::name('admin_token')->where('user_id', $row['id'])->update([
                        'create_time' => time(),
                        'expire_time' => time() + 2 * 3600,
                        'token' => $token
                    ]);
                // 提交事务
                Db::commit();
                LoginLog::LoginSuccessLog($param, '登录成功', time());
                $this->success('success', ['code' => 200, 'data' => ['username' => $row['username'], 'token' => $token]]);
            } catch (Exception $e) {
                // 执行回滚
                Db::rollback();
                LoginLog::LoginErrorLog($param, $e->getMessage(), time());
                $this->error('error', $e->getMessage(), 202);
            }
        } else {
            LoginLog::LoginErrorLog($param, '登录信息错误', time());
            $this->error('error', ['code' => 201, 'data' => '登信息错误']);
        }
        exit(0);
    }

    /** QQ登录
     * @throws DataNotFoundException
     * @throws ModelNotFoundException
     * @throws DbException
     */
    public function login_by_qq()
    {
        // 接收前端的openID-qq
        $param = Request::instance()->post() ?? [];
        // 接收前端IP
        $requestIp = Request::instance()->ip() ?? '0.0.0.0';
        $param['login_ip'] = $requestIp;
        // 校验接收数据合法性
        $validRes = $this->validate($param, 'Admin.qq_login');
        if ($validRes !== true) {
            LoginLog::LoginErrorLog($param, $validRes, time());
            $this->error('error', ['code' => 201, 'data' => $validRes]);
        }
        // 校验app_id是否合法
        $configAppId = Db::name('config')->where('name', '=', 'qq_app_id')->find()['value'];
        if ($configAppId !== $param['qq_app_id']) {
            LoginLog::LoginErrorLog($param, 'appid不正确', time());
            $this->error('error', ['code' => 201, 'data' => 'appid不正确']);
        } else {
            // 校验用户是否存在,不存在则新建
            $row = \app\api\model\Admin::get(['qq_open_id' => $param['qq_open_id']]);
            Db::startTrans();
            try {
                // 创建用户
                if (empty($row)) {
                    // 获取当前时间戳
                    $currentTime = time();
                    // 生成密码
                    $generatePwd = self::generatePassword('123456');
                    $newAdmin = new \app\api\model\Admin();
                    $newAdmin->data([
                        'username' => Util::random(6, 'all'),
                        'salt' => $generatePwd['salt'],
                        'password' => $generatePwd['encryptPassword'],
                        'status' => 1,
                        'create_time' => $currentTime,
                        'login_time' => $currentTime,
                        'token' => md5($currentTime),
                        'qq_open_id' => $param['qq_open_id'],
                        'gender' => 0
                    ]);
                    $newAdmin->save();
                    // 存入AdminToken表
                    $AdminToken = AdminToken::get(['user_id' => $row['id']]) ?? '';
                    $AdminToken == '' ?
                        Db::name('admin_token')->insert([
                            'token' => $newAdmin['token'],
                            'user_id' => $newAdmin['id'],
                            'create_time' => time(),
                            'expire_time' => time() + 2 * 3600
                        ])
                        :
                        Db::name('admin_token')->where('user_id', $row['id'])->update([
                            'create_time' => time(),
                            'expire_time' => time() + 2 * 3600,
                            'token' => $newAdmin['token']
                        ]);
                    Db::commit();
                    LoginLog::LoginSuccessLog($param, '创建用户' . $newAdmin, time());
                    $this->success('success', ['code' => 200, 'data' => ['username' => $newAdmin['username'], 'token' => $newAdmin['token']]]);
                } else {
                    // 生成token
                    $token = md5($row['id'] . time());
                    $row['token'] = $token;
                    $row['login_time'] = time();
                    $row['login_ip'] = $requestIp;
                    $row->save();
                    // 存入AdminToken表
                    $AdminToken = AdminToken::get(['user_id' => $row['id']]) ?? '';
                    $AdminToken == '' ?
                        Db::name('admin_token')->insert([
                            'token' => $token,
                            'user_id' => $row['id'],
                            'create_time' => time(),
                            'expire_time' => time() + 2 * 3600
                        ])
                        :
                        Db::name('admin_token')->where('user_id', $row['id'])->update([
                            'create_time' => time(),
                            'expire_time' => time() + 2 * 3600,
                            'token' => $token
                        ]);
                    Db::commit();
                    LoginLog::LoginSuccessLog($param, '登录成功', time());
                    $this->success('success', ['code' => 200, 'data' => ['username' => $row['username'], 'token' => $token]]);
                }
            } catch (Exception $e) {
                Db::rollback();
                LoginLog::LoginErrorLog($param, $e->getMessage(), time());
                $this->error('error', $e->getMessage(), 202);
            }
        }
    }

    /**
     * 通过qq的openID获取access_token
     */
    public function get_openid_by_access_token()
    {
        // 接收access_token
        $param = Request::instance()->post() ?? [];
        empty($param) && $this->error('error', ['code' => 201, 'access_token不能为空!']);
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, 'https://graph.qq.com/oauth2.0/me?access_token=' . $param['access_token'] . '&fmt=json');
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_HEADER, false);
        $data = json_decode(curl_exec($ch));
        curl_close($ch);
        $this->success('success', ['code' => 200, 'data' => $data]);
    }

    /**
     * 获取
     * @throws DataNotFoundException
     * @throws ModelNotFoundException
     * @throws DbException
     */
    public function lists()
    {
        // 定义日志参数
        $options = array(
            'title' => '获取管理员列表',
            'method' => Request::instance()->action(),
            'request_method' => Request::instance()->method(),
            'open_url' => Request::instance()->url(),
            'oper_ip' => Request::instance()->ip(),
            'token' => Request::instance()->header('token')
        );
        // 查询可显示字段
        $field = [
            'id', 'username', 'nickname', 'login_ip', 'status', 'login_time', 'create_time', 'root',
        ];
//        $admin_lists = Db::name('admin')
//            ->field('id,username,nickname,login_ip,status,login_time,create_time,root')
//            ->select();
        // 定义接收前端参数where
        $where = Request::instance()->param('where/a') ?? [];
        $admin_lists = (new \app\api\model\Admin)
            ->field($field)
            ->with('group')
            ->where(self::build_params($where))
            ->select();
        OperationLog::OperSuccess($where, $options, 'R', $admin_lists);
        $this->success('success', ['code' => 200, 'data' => $admin_lists]);
    }

    /**
     * 生成验证码
     * @return Response
     */
    public function generate_captcha(): Response
    {
        $captcha = new Captcha();
        return $captcha->entry();
    }

    /**
     * 管理员添加方法
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public function add()
    {
        // 定义日志参数
        $options = array(
            'title' => '添加管理员',
            'method' => Request::instance()->action(),
            'request_method' => Request::instance()->method(),
            'open_url' => Request::instance()->url(),
            'oper_ip' => Request::instance()->ip(),
            'token' => Request::instance()->header('token')
        );
        $param = Request::instance()->param() ?? [];
        $validRes = $this->validate($param, 'Admin.add');
        if ($validRes !== true) {
            OperationLog::OperError($param, $options, 'C', $validRes);
            $this->error('error', ['code' => 201, 'data' => $validRes]);
        }
        // 密码加密
        $param['password'] = md5($param['password']);
        // 校验用户名是否存在
        $checkExistUserName = \app\api\model\Admin::get(['username' => $param['username']]);
        if (!empty($checkExistUserName)) {
            OperationLog::OperError($param, $options, 'C', '用户名已存在!');
            $this->error('error', ['code' => 201, 'data' => '用户名已存在!']);
        } else {
            // 校验角色是否存在
            $checkRoleExist = SystemRole::get(['id' => $param['role_id']]);
            if (empty($checkRoleExist)) {
                OperationLog::OperError($param, $options, 'C', '角色不存在!');
                $this->error('error', ['code' => 201, 'data' => '角色不存在!']);
            } else {
                /**
                 * 生成密码、密码盐、root
                 * 保留role_id并生成roleData
                 * 删除$param的role_id
                 */
                $saltAndPassword = Api::generatePassword($param['password']);
                $param['salt'] = $saltAndPassword['salt'];
                $param['password'] = $saltAndPassword['encryptPassword'];
                $param['root'] = 0;
                $roleData = [
                    'role_id' => $param['role_id']
                ];
                unset($param['role_id']);
                Db::startTrans();
                try {
                    $admin = \app\api\model\Admin::create($param);
                    if ($admin['id']) {
                        $roleData['admin_id'] = $admin['id'];
                        AdminRole::where(['admin_id' => $admin['id']])->delete();
                        AdminRole::create($roleData);
                        Db::commit();
                        OperationLog::OperSuccess($param, $options, 'C', '操作成功!');
                        $this->success('success', ['code' => 200, 'data' => '操作成功!']);
                    } else {
                        Db::rollback();
                        OperationLog::OperError($param, $options, 'C', '操作失败!');
                        $this->error('error', ['code' => 201, 'data' => '操作失败!']);
                    }
                } catch (Exception $e) {
                    Db::rollback();
                    OperationLog::OperError($param, $options, 'C', $e->getMessage());
                    $this->error('error', $e->getMessage(), 202);
                }
            }
        }
    }

    /**
     * 查看管理员详情
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public function detail()
    {
        // 定义日志参数
        $options = array(
            'title' => '查看管理员信息',
            'method' => Request::instance()->action(),
            'request_method' => Request::instance()->method(),
            'open_url' => Request::instance()->url(),
            'oper_ip' => Request::instance()->ip(),
            'token' => Request::instance()->header('token')
        );
        $param = Request::instance()->param() ?? [];
        $validRes = $this->validate($param, 'Admin.detail');
        if ($validRes !== true) {
            OperationLog::OperError($param, $options, 'R', $validRes);
            $this->error('error', ['code' => 201, 'data' => $validRes]);
        }
        $admin = \app\api\model\Admin::where(['id' => $param['id']])
            ->with('group')
            ->column('id, nickname, root,status, username, group.role_id as role_id');
        if (empty($admin)) {
            OperationLog::OperError($param, $options, 'R', '账户不存在!');
            $this->error('error', ['code' => 201, 'data' => '账户不存在!']);
        }
        OperationLog::OperSuccess($param, $options, 'R', $admin[$param['id']]);
        $this->success('success', ['code' => 200, 'data' => $admin[$param['id']]]);
    }

    public function edit()
    {
        // 定义日志参数
        $options = array(
            'title' => '编辑管理员信息',
            'method' => Request::instance()->action(),
            'request_method' => Request::instance()->method(),
            'open_url' => Request::instance()->url(),
            'oper_ip' => Request::instance()->ip(),
            'token' => Request::instance()->header('token')
        );
        $param = Request::instance()->param() ?? [];
        $validRes = $this->validate($param, 'Admin.detail');
        if ($validRes !== true) {
            OperationLog::OperError($param, $options, 'U', $validRes);
            $this->error('error', ['code' => 201, 'data' => $validRes]);
        }
        // 加密密码
        $param['password'] = md5($param['password']);
        // 校验用户名是否存在
        $checkExistUserName = \app\api\model\Admin::get(['username' => $param['username']]);
        if (!empty($checkExistUserName) && $checkExistUserName['id'] != $param['id']) {
            OperationLog::OperError($param, $options, 'U', '用户名已存在!');
            $this->error('error', ['code' => 201, 'data' => '用户名已存在!']);
        } else {
            // 校验角色是否存在
            $checkRoleExist = SystemRole::get(['id' => $param['role_id']]);
            if (empty($checkRoleExist)) {
                OperationLog::OperError($param, $options, 'U', '角色不存在!');
                $this->error('error', ['code' => 201, 'data' => '角色不存在!']);
            } else {
                // 检查用户是否存在
                $admin = \app\api\model\Admin::get(['id' => $param['id']]);
                /**
                 * 判断密码盐是否存在，存在则直接加密
                 * 否则生成密码、密码盐、root
                 * 保留role_id并生成roleData
                 * 删除$param的role_id
                 */
                if (!empty($checkExistUserName['salt'])) {
                    $param['password'] = Api::decryptPassword($param['password'], $admin['salt']);
                } else {
                    $saltAndPassword = Api::generatePassword($param['password']);
                    $param['salt'] = $saltAndPassword['salt'];
                    $param['password'] = $saltAndPassword['encryptPassword'];
                }
                if ($admin['root'] == 0) {
                    $roleData = [
                        'role_id' => $param['role_id']
                    ];
                    unset($param['role_id']);
                }
                Db::startTrans();
                try {
                    $admin->save($param, ['id' => $param['id']]);
                    if ($admin['root'] == 0) {
                        $roleData['admin_id'] = $admin['id'];
                        AdminRole::where(['admin_id' => $admin['id']])->delete();
                        AdminRole::create($roleData);
                    }
                    Db::commit();
                    OperationLog::OperSuccess($param, $options, 'U', '操作成功!');
                    $this->success('success', ['code' => 200, 'data' => '操作成功!']);
                } catch (Exception $e) {
                    Db::rollback();
                    OperationLog::OperError($param, $options, 'U', $e->getMessage());
                    $this->error('error', $e->getMessage(), 202);
                }
            }
        }
    }

    public function del()
    {
        // 定义日志参数
        $options = array(
            'title' => '删除管理员',
            'method' => Request::instance()->action(),
            'request_method' => Request::instance()->method(),
            'open_url' => Request::instance()->url(),
            'oper_ip' => Request::instance()->ip(),
            'token' => Request::instance()->header('token')
        );
        $param = Request::instance()->param() ?? [];
        $validRes = $this->validate($param, 'Admin.del');
        if ($validRes !== true) {
            OperationLog::OperError($param, $options, 'D', $validRes);
            $this->error('error', ['code' => 201, 'data' => $validRes]);
        }
        // 判断用户是否存在和是否为root用户
        $checkIllegal = \app\api\model\Admin::get(['id' => $param['id']]);
        if (empty($checkIllegal)) {
            OperationLog::OperError($param, $options, 'D', '用户不存在!');
            $this->error('error', ['code' => 201, 'data' => '用户不存在!']);
        } else {
            if ($checkIllegal['root'] == 1) {
                OperationLog::OperError($param, $options, 'D', '此账户不能删除!');
                $this->error('error', ['code' => 201, 'data' => '此账户不能删除!']);
            } else {
                Db::startTrans();
                try {
                    $checkIllegal->delete(true);
                    Db::commit();
                    OperationLog::OperSuccess($param, $options, 'D', '操作成功!');
                    $this->success('success', ['code' => 200, 'data' => '操作成功!']);
                } catch (Exception $e) {
                    Db::rollback();
                    OperationLog::OperError($param, $options, 'D', $e->getMessage());
                    $this->error('error', $e->getMessage(), 202);
                }
            }
        }
    }

    /**
     * 测试方法
     */
    public function test()
    {
        $param = Request::instance()->file() ?? [];
        print_r($param);
//        var_dump($param);
//        $mail = new Mail();
//        $res = $mail->sendEmail(
//            ['1684733955@qq.com'],
//            '测试邮件主题' . time(),
//            '<h1>这里是邮件内容</h1>' . date('Y-m-d H:i:s'),
//            '如果邮件客户端不支持HTML则显示此内容');
//        if ($res) {
//            $this->success('success', ['code' => 200, 'data' => '邮件发送成功']);
//        } else {
//            $this->error('error', ['code' => 201, 'data' => '邮件发送失败']);
//        }
//        $captcha = new Captcha();
//        return $captcha->entry();
//        $validRes = $this->validate($param,'Admin.test');
//        print($validRes);
//        return PHP_OS;
//        try {
//            $upload = new Upload();
//            $upload->setFile($param['file']);
//            $upload->upload();
////            print_r($upload);
//        } catch (Exception $e) {
////            var_dump($e);
//            print_r($e->getMessage());
////            $this->error('error', ['code' => 202, 'data' => $e->getMessage()], '202');
//        }
//        print_r($upload);
    }
}